package com.example.drawing.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;


/**
 * Q1：这个画板放在哪里？
 * 答：View里，我们自定义一个View，在onDraw()里完成绘制，另外View还有个onTouchEvent的方法， 我们可以在获取用户的手势操作！
 *
 * Q2.需要准备些什么？
 *
 * 答：一只画笔(Paint)，一块画布(Canvas)，一个路径(Path)记录用户绘制路线；
 * 另外划线的时候，每次都是从上次拖动时间的发生点到本次拖动时间的发生点！
 * 那么之前绘制的 就会丢失，为了保存之前绘制的内容，我们可以引入所谓的"双缓冲"技术：
 * 其实就是每次不是直接绘制到Canvas上，而是先绘制到Bitmap上，等Bitmap上的绘制完了， 再一次性地绘制到View上而已！
 *
 * Q3.具体的实现流程？
 *
 * 答：初始化画笔，设置颜色等等一些参数；在View的onMeasure()方法中创建一个View大小的Bitmap，
 * 同时创建一个Canvas；onTouchEvent中获得X,Y坐标，做绘制连线，最后invalidate()重绘，
 * 即调用 onDraw方法将bitmap的东东画到Canvas上！
 */
public class DrawingView extends View {
    private Paint mPaint;  //绘制线条的Path
    private Path mPath;      //记录用户绘制的Path
    private Canvas mCanvas;  //内存中创建的Canvas
    private Bitmap mBitmap;  //缓存绘制的内容

    private int mLastX;
    private int mLastY;

    public DrawingView(Context context) {
        super(context);
        init();

    }

    public DrawingView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public DrawingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public DrawingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }



    private void init(){
        mPath = new Path(); //设置路径
        mPaint = new Paint();   //初始化画笔
        mPaint.setColor(Color.RED);//画笔颜色
        mPaint.setAntiAlias(true);//画笔抗锯齿
        mPaint.setDither(true);//画笔防抖动。
        mPaint.setStyle(Paint.Style.STROKE);//画笔模式为填充
        mPaint.setStrokeJoin(Paint.Join.ROUND); //结合处为圆角
        mPaint.setStrokeCap(Paint.Cap.ROUND); // 设置转弯处为圆角
        mPaint.setStrokeWidth(30);   // 设置画笔宽度
    }
    @Override
    /**
     * 当子View的父控件要放置该View的时候，父控件会传递两个参数给View——widthMeasureSpec和heightMeasureSpec。
     */
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);//父方法
        int width = getMeasuredWidth();//获取宽度
        int height = getMeasuredHeight();//获取宽度
        // 初始化bitmap,Canvas
        mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);//根据屏幕创建位图
        mCanvas = new Canvas(mBitmap);//根据位图创建缓存画板
    }

    @Override
    /**
     * 绘图
     */
    protected void onDraw(Canvas canvas) {
        drawPath();
        System.out.println(mBitmap);
        canvas.drawBitmap(mBitmap, 0, 0, null);//绘制
    }
    //绘制线条
    private void drawPath(){
        mCanvas.drawPath(mPath, mPaint);//作用仅仅在于承接我们的画笔操作，然后将所相应位置的像素存储到相应的Bitmap中。
    }

    @Override
    /**
     * onTouchEvent的方法， 可以在获取用户的手势操作
     * 参数event为手机屏幕触摸事件封装类的对象，其中封装了该事件的所有信息，
     * 例如触摸的位置、触摸的类型以及触摸的时间等。该对象会在用户触摸手机屏幕时被创建。
     */
    public boolean onTouchEvent(MotionEvent event) {

        int action = event.getAction();//触摸动作的原始32位信息，包括事件的动作，触控点信息
        int x = (int) event.getX();//是相对当前的控件左上角的X距离
        int y = (int) event.getY();//是相对当前的控件左上角的Y距离

        switch (action)
        {
            case MotionEvent.ACTION_DOWN://在第一个点被按下时触发
                mLastX = x;
                mLastY = y;
                mPath.moveTo(mLastX, mLastY);//moveTo 不会进行绘制，只用于移动画笔
                break;
            case MotionEvent.ACTION_MOVE:  //当有点在屏幕上移动时触发。值得注意的是，由于它的灵敏度很高，而我们的手指又不可能完全静止（即使我们感觉不到移动，但其实我们的手指也在不停地抖动），所以实际的情况是，基本上只要有点在屏幕上，此事件就会一直不停地被触发。
                int dx = Math.abs(x - mLastX);
                int dy = Math.abs(y - mLastY);
                if (dx > 3 || dy > 3)  //当移动超过3的时候连接
                    mPath.lineTo(x, y);//lineTo是直接 起点与 终点相连
                mLastX = x;
                mLastY = y;
                break;
        }
        System.out.println("mLastX:"+mLastX);
        System.out.println("mLastY:"+mLastY);
        invalidate();//刷新屏幕
        return true;
    }
}
